﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace CL20181.Sock
{
    internal class UDPClient
    {
        /// <summary>
        /// 本地绑定端口
        /// </summary>
        private int UdpBindPort;

        private Socket Client;

        List<byte> RevItems = new List<byte>();     //接收的数据集合

        /// <summary>
        /// 接收数据缓存
        /// </summary>
        byte[] recvBuff = new byte[1024];
        /// <summary>
        /// 远程通信点
        /// </summary>
        private IPEndPoint Point = new IPEndPoint(IPAddress.Parse("193.168.18.1"), 10003);
        /// <summary>
        /// 通信参数
        /// </summary>
        private string m_Setting = "1200,e,8,1";

        private bool m_IsInit = false;

        /// <summary>
        /// 设置 侦超时时间 
        /// </summary>
        public long FrameTimeOut
        {
            get;
            set;
        }

        /// <summary>
        /// 设置字节超时时间
        /// </summary>
        public long BitTimeOut
        {
            get;
            set;
        }

        /// <summary>
        /// 是否初始化
        /// </summary>
        public bool IsInit
        {
            get { return m_IsInit; }
        }

        public UDPClient()
        {
            this.FrameTimeOut = 2000;
            this.BitTimeOut = 500;
        }

        /// <summary>
        /// 初始化通信模块
        /// </summary>
        /// <param name="Setting">通信参数（1200,e,8,1）</param>
        /// <param name="IP">IP地址</param>
        /// <param name="BindPort">本地绑定端口</param>
        /// <param name="BindSetPort">本地绑定设置端口</param>
        /// <param name="RemotePort">远程端口</param>
        public void Init(string Setting, string IP, int BindPort, int BindSetPort, int RemotePort, int frameTimeOut, int bitTimeOut)
        {
            m_Setting = Setting;
            Point.Address = IPAddress.Parse(IP);
            Point.Port = RemotePort;
            UdpBindPort = BindPort;
            byte[] SendArr = ASCIIEncoding.ASCII.GetBytes(string.Format("init {0}", m_Setting.Replace(',', ' ')));
            this.FrameTimeOut = frameTimeOut;
            this.BitTimeOut = bitTimeOut;
            this.Client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            this.Client.Connect(Point);
            m_IsInit = SendData(BindSetPort, ref  SendArr, false);           //发送初始化参数
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="Port">端口</param>
        /// <param name="vData">发送的二进制数据</param>
        /// <param name="IsReturn">是否需要返回</param>
        /// <returns></returns>
        private bool SendData(int Port, ref Byte[] vData, bool IsReturn)
        {
            RevItems.Clear();
            Client.ReceiveTimeout = (int)this.FrameTimeOut;
            //发送数据
            Client.Send(vData);

            if (!IsReturn) // 如果不需要数据返回 
            {
                vData = this.RevItems.ToArray();
                return true;
            }
            int readed = 0;
            readed = ReadUDPSocketData(Client, recvBuff);
            if (readed > 0)
            {
                for (int i = 0; i < readed; i++)
                {
                    RevItems.Add(recvBuff[i]);
                }
                Client.ReceiveTimeout = (int)this.BitTimeOut;
                while (true)         //没一个包块延时200毫秒检测是否存在断包的情况
                {
                    readed = ReadUDPSocketData(Client, recvBuff);
                    if (readed <= 0)
                        break;
                    else
                    {
                        for (int i = 0; i < readed; i++)
                        {
                            RevItems.Add(recvBuff[i]);
                        }
                    }
                }
            }
            vData = RevItems.ToArray();
            return vData.Length > 0;
        }

        private int ReadUDPSocketData(Socket s, byte[] buff)
        {
            try
            {
                return s.Receive(buff);
            }
            catch (SocketException se)
            {
                return -1;
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="vData">发送的二进制数据</param>
        /// <param name="IsReturn">是否需要返回</param>
        /// <returns></returns>
        public bool SendData(ref byte[] vData, bool IsReturn)
        {
            if (!m_IsInit) return false;
            return SendData(UdpBindPort, ref vData, IsReturn);
        }
    }
}
